﻿using System;
using System.Drawing;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Threading;
namespace AiMoInGH.Pipeline
{
    class PipeServer
    {

        readonly string m_CurrentServerName;
        StreamWriter Writer { get; }
        StreamReader Reader { get; }
        NamedPipeServerStream Server { get; }

        readonly GrasshopperBridgeInfo m_BridgeInfo;
        public bool Connected => Server.IsConnected;
        public PipeServer()
        {
#if DEBUGGH
            m_CurrentServerName = "AimoPipe_GH_123456";
#else
            m_CurrentServerName = "AimoPipe_GH_" + Guid.NewGuid().ToString();
#endif
            m_BridgeInfo = new GrasshopperBridgeInfo();
            Server = new NamedPipeServerStream(m_CurrentServerName, PipeDirection.InOut);
            Reader = new StreamReader(Server);
            Writer = new StreamWriter(Server);
        }
        /// <summary>
        /// 打开之后就会新开一个AiMo
        /// </summary>
        public void OpenNewAiMoWindow(string aimoExePath, GHExecutorInfo executorInfo)
        {
            new Thread(() => { StartServerAsync(aimoExePath, executorInfo); }).Start();

        }
        void StartServerAsync(string path, GHExecutorInfo executorInfo)
        {

            executorInfo.SendFirstScriptToAimoWindow(m_CurrentServerName);

#if DEBUG
            Rhino.RhinoApp.WriteLine($"Start AiMoExe {path} at {DateTime.Now}");
#endif

#if DEBUGGH
            Rhino.RhinoApp.WriteLine($"Debug: AiMo GH Start Server Pipeline at {DateTime.Now}");
#else
            System.Diagnostics.Process process = System.Diagnostics.Process.Start(path, m_CurrentServerName);
            if (process == null)
            {
                Eto.Forms.MessageBox.Show("Cannot Start Aimo [0090]");
                return;
            }
#endif
            try
            {
                Server.WaitForConnection();
#if DEBUG || DEBUGGH
                Rhino.RhinoApp.WriteLine($"Debug: AiMo Server Connected Done at {DateTime.Now}");
#endif
                while (true)
                {
                    string data = Reader.ReadLine();
                    {
                        if (data == null)
                        {
                            //当对方退出后，会回复null
                            break;
                        }
                        else if (data == "Connected")
                        {
                            string hasBlockEdit = m_BridgeInfo.HasBlockEdit ? "HasBlockEdit" : "NoBlockEdit";
                            string content = Join(hasBlockEdit, m_BridgeInfo.CurrentRhinoVersion, Join(m_BridgeInfo.RhinoAssemblyLocations));
                            SendOneLine(content);
                        }
                        else if (data.StartsWith("ScreenShot-"))
                        {
                            string[] values = data.Split('-');
                            int width = int.Parse(values[1]);
                            int height = int.Parse(values[2]);
                            SendScreenShotBitmap(width, height);
                        }
                        else if (data.StartsWith("Run-"))
                        {
                            //从AiMo过来，发给Rhino
                            executorInfo.SetInfo(Split(data.Substring(7)), data.StartsWith("Run-CN-"));
                            bool runResult = executorInfo.Run();
                            SendOneLine(Join(PipeUtils.EndFlag, runResult.ToString(), "", executorInfo.RunCommandError));
                        }
                        else if (data.Contains("Test Connected"))
                        {
                            SendOneLine("Received");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (!m_Disposed)
                {
                    Eto.Forms.MessageBox.Show($"AiMoGH external pipeline disconnected unexpected: \r\n   {ex.Message}\r\n    {ex.StackTrace}");
                    Dispose();
                }
            }
        }
        void SendScreenShotBitmap(int width, int height)
        {
            Size size = new Size(width, height);
            string content = "";
            try
            {
                Bitmap bitmap = m_BridgeInfo.GetScreenShot(size);

                if (bitmap != null)
                {
                    MemoryStream stream = new MemoryStream();
                    bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    byte[] imgBytes = stream.GetBuffer();
                    content = Convert.ToBase64String(imgBytes);
                    stream.Close();
                    stream.Dispose();
                }
            }
            catch { }
            SendOneLine(content);
        }
        void SendOneLine(string content)
        {
            Writer.WriteLine(content);
            Server.WaitForPipeDrain();
            Writer.Flush();
        }
        string[] Split(string contents)
        {
            return contents.Split(new string[] { PipeUtils.Spliter }, StringSplitOptions.None).Select(x => x.Replace(PipeUtils.ReturnFlag, "\r\n")).ToArray();
        }
        string Join(params string[] separator)
        {
            return string.Join(PipeUtils.Spliter, separator.Select(x => x.Replace("\r\n", PipeUtils.ReturnFlag)));
        }
        bool m_Disposed = false;
        public void Dispose()
        {
            try
            {
                Server.Close();
                Server.Dispose();
                Reader.Close();
                Reader.Dispose();
                Writer.Close();
                Writer.Dispose();
                m_Disposed = true;
            }
            catch { }
        }

    }
}
